<?php
/*
*作者:小松科技
*时间:2020.7.17
*myBlog:http://www.xskj.store
*文档:设置token,api填写该类路由，请使用thinkphp框架定义控制器
*微信公众号操作类
*thinkphp建立api模块Wechat类
*微信配置url:http://你的域名/index.php/tokenApi【说明:如果你把public作为根目录则url为:http://你的域名/tokenApi
*/
namespace  app\api\controller;
use think\Controller;
use think\Db;
use thiagoalessio\TesseractOCR\TesseractOCR;
use think\Cache;



class Wechat extends Controller
{



   public function wechat()//主入口
  {
      
      
      
 //token验证
 if(isset($_GET['echostr']))//微信服务器发送来的
 {

    $signature = $_GET["signature"];
    $timestamp = $_GET["timestamp"];
    $nonce = $_GET["nonce"];
    
    //读取数据库获取token值
    		
    $web=Db::name('websystem')->find();
    
    $token = $web["wechat_token"];
    $tmpArr = array($token, $timestamp, $nonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode( $tmpArr);
    $tmpStr = sha1( $tmpStr );
    // return $_GET['echostr'];
   
    
    if( $tmpStr == $signature ){
        // return true;
      return $_GET['echostr'];
   
    }else{
        return false;
    }
  }
  
        //自动回复操作
        $postStr = file_get_contents('php://input');//php7.0以上用这个接收参数
        
        //extract post data
        if(!empty($postStr)){
         
            //解析post来的XML为一个对象$postObj
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
 
            $fromUsername = $postObj->FromUserName; //请求消息的用户
            $toUsername = $postObj->ToUserName; //"我"的公众号id
            $Content = trim($postObj->Content); //消息内容
            $time = time(); //时间戳
            $msgtype = 'text'; //消息类型：文本
            $MsgId = (string)$postObj->MsgId;
            $textTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[%s]]></MsgType>
            <Content><![CDATA[%s]]></Content>
            </xml>"; 
            
            
            // echo $MsgId;
            
            //订阅公众号自动回复
            if(strtolower($postObj->MsgType == 'event' )){ //如果XML信息里消息类型为event
                if($postObj->Event == 'subscribe'){ //如果是订阅事件
                
                    //回复内容       
                   $subscribe=Db::name('websystem')->find();			
			       if(empty($subscribe)){
			       //默认
			         $contentStr="欢迎使用！";
			       }else{
			         $contentStr=$subscribe["subscribe"];
			       }
                    $resultStrq = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
                    echo $resultStrq;
                    exit();
                }
            }
            
            
           //文本信息
           if(strtolower($postObj->MsgType == 'text' )){ 
               
                //关键词回复------逻辑回复----采用前缀关键词----默认查询题库接口
               $keyword = Db::name('wechat_public')->where('keywords', $Content)->find();
               if (!empty($keyword)) {
                  //关键词存在\\\关键词自动回复
                  $contentStr = $keyword["reply_word"];
               }else{
                    //关键词回复-----采用前缀标识规则开关---
                $preKeyword = explode(' ', $Content);
                
   
                $pre=Db::name('wechat_public_auto_text')->where('preKeyword', $preKeyword[0])->find();
     
                if(!empty($pre)){
                    // 前缀关键词匹配成功
                     $isMatched = preg_match('/^'.$preKeyword[0].'[^a-zA-Z0-9s|](.*)/', $Content, $matches);
                     
                    //  获得内容
                    $content = $matches[count($matches)-1];
                    
                    // 查询结果
                    $contentStr = $this->autoText($pre["ruler"],$content);
                }else{
                    // 调用默认接口
                    $pre2 = Db::name("wechat_site")->find();
                    $contentStr = $this->autoText($pre2["default_textAuto"],$Content);
                }
              }
            
            $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
            return $resultStr;
        }
            
        
            //图片信息
       if(strtolower($postObj->MsgType == 'image' )){ 
                //获取图片url
                $PicUrl=$postObj->PicUrl; 
                //这里进行业务处理逻辑↓↓↓↓↓↓(可以对该图片进行业务处理)
                $site = Db::name("wechat_site")->find();
               
                 if( $site["picture_model"] == 0){
                      // 上传图片接口
                    $re =  $this->downloadFileToDir($PicUrl, $toUsername);
                    if($re==1){
                        $contentStr = "上传图片成功！";
                    }else{
                        $contentStr = "上传图片失败！";
                    }
                 }else if($site["picture_model"] == 1){
                    //  图片文字搜索接口
                     $data = $this->getText($PicUrl, $MsgId);
                     if($data == null){
                        //  没有文字识别到
                        $contentStr = "图片不符合规定，没有识别到该图片文字！";
                     }else{
                        //  搜索题库
                        //  文字提取处理

                        $data_array =$this->getKeyword($data);
                        
                        // dump($data_array);
                        $contentStr = "没能查询到！";
                        
                        for($i = count($data_array)-1; $i >= 0 ; $i--){
                            
                            // var_dump($data_array[$i]);
                            // 循环遍历查找
                            $a=Db::name('answer_source')->where('question','like', "%".$data_array[$i]."%")->find();
                            
                            // dump($a);
                            if(!empty($a)){
                                // 跳出循环
                                $contentStr = "问题:".$a["question"]."\n答案:".$a["answer"];
                                break;
                            }
                        
                        }
                     }
                 }else{
                    //  图像文字识别提取
                     $data = $this->getText($PicUrl, $MsgId);
                     if($data == null){
                        //  没有文字识别到
                        $contentStr = "图片不符合规定，提取文字失败！";
                     }else{
                        $contentStr ="文字提取结果:\n".$data;
                     }
                 }
                 
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
                return $resultStr;
            }
            
            
          //链接信息
         if(strtolower($postObj->MsgType == 'link' )){ 
                //获取链接url
                $Url=$postObj->Url; //消息链接url
                $Title=$postObj->Title; //消息标题
                $Description=$postObj->Description;  //消息描述
                //这里进行业务处理逻辑↓↓↓↓↓↓(可以对该url链接进行业务处理)
                
                //默认回复文本
                $contentStr="链接地址为:".$Url;
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
                return $resultStr;
         }
         
         //地理信息
         if(strtolower($postObj->MsgType == 'location' )){ 
                
                $Location_X=$postObj->Location_X; //地理纬度
                $Location_Y=$postObj->Location_Y; //地理经度
                $Scale=$postObj->Scale;            //地图缩放大小
                $Label=$postObj->Label;           //地理位置信息
                //这里进行业务处理逻辑↓↓↓↓↓↓(可以对该地理信息进行业务处理)
                
                //默认回复文本
                $contentStr="您当前位于:\n纬度:".$Location_X."\n经度:".$Location_Y."\n地图缩放:".$Scale."\n地理位置信息:".$Label;
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgtype, $contentStr);
                return $resultStr;
           }
        }else {
            echo "error";
            exit();
        }
}



    //   冒泡算法
    private function maopao($arr){

    $len = count($arr);

    for($k=0;$k<=$len;$k++)

    {

        for($j=$len-1;$j>$k;$j--){

            if(strlen($arr[$j])<strlen($arr[$j-1])){

                $temp = $arr[$j];

                $arr[$j] = $arr[$j-1];

                $arr[$j-1] = $temp;

            }

        }

    }
    return $arr;
}

  



   //文本关键词提取函数---返回数组
   private function getKeyword($text){
       
    if(preg_match_all('/[\x{4e00}-\x{9fa5}]+/u', $text, $matches1)){
    
    preg_match_all('/[^0-9|,|、][\x{4e00}-\x{9fa5}a-zA-Z0-9_、，]+/u', $text, $matches);
    // // 存在中文
    // dump($matches);
    
    $data = $this->maopao($matches[0]);
    }else{
    // 其他字符
    preg_match_all('/[^0-9|、|,|\s][A-Za-z0-9_ ]+/u', $text, $matches);  //这里有空格，注意
    //  dump($matches);
    
    $data =$this->maopao($matches[0]);
    }
      return $data;
    }



    // 下载文件到指定目录
    private function downloadFileToDir($url, $toUsername){
        
         // 文件流
         $ch = curl_init ();  
         curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, 'GET' );  
         curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, false );  
         curl_setopt ( $ch, CURLOPT_URL, $url );  
         ob_start ();  
         curl_exec ( $ch );  
         $return_content = ob_get_contents ();  
         ob_end_clean ();  
         $return_code = curl_getinfo ( $ch, CURLINFO_HTTP_CODE );
         
          //生成随机字符串
         $strs="QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
         $name=substr(str_shuffle($strs),mt_rand(0,strlen($strs)-11),10);
         
         
         $file_type="png";//文件类型
         $filename = $_SERVER['DOCUMENT_ROOT']."/upload/image/".date("YmdHis").$name.".".$file_type;
         
         // 获取是否审核
         $switch = Db::name('websystem')->find();
         
         $fp= fopen($filename,"a"); //将文件绑定到流
         
         if(fwrite($fp,$return_content)){
             
              //数据封装
             $data=array(
              'file_path'=>"/upload/image/".date("YmdHis").$name.".".$file_type,
              'classify'=>"公众号上传",
              'file_type'=>$file_type,
              'status'=>$switch["upload_audit_switch"],   //默认需要不审核 
              'user'=>$toUsername,
              'file_size'=>"未知",   //b为单位
              'description'=>"公众号用户上传",
              'user_defined_label'=>"公众号",
              'doc_id'=>$toUsername
               );
              //添加数据
              $result=Db::name("upload_file_source")->insert($data);
              
              if(!empty($result)){
                   fclose($fp);
                   return 1;
              }
         }
    }
    
  
  


 
 
   


//   文本自动回复规则函数
private function autoText($ruler, $content){
                      //  广告设置
                       $ad = Db::name("wechat_site")->where('id',1)->find();  
                       
                       // 默认文本自动回复-（0 题库，1 资源，2 文档 ，3 图片， 4, 资讯） 
                       $contentStr = "搜索结果：";
                      //题库
                      if($ruler == 0){
                          $data=Db::name('answer_source')->where('question','like', "%".$content."%")->find();
                          if(!empty($data)){
                             $contentStr =$ad["ad_header"]."\n"."问题:".$data["question"]."\n答案:".$data["answer"]."\n\n".$ad["ad_footer"];
                          }else{
                              $contentStr = "抱歉！没能查询到";
                          }
                       }
                      
                       // 资源
                       if($ruler == 1){
                          $data=Db::name('source')->where('description','like', "%".$content."%")->limit(10)->select();
                          if(!empty($data)){
                              
                             foreach ($data as $key=>$value){
                                 $contentStr = $contentStr."\n\n"."描述:".$value["description"]." 链接:".$value["download_url"]." 密码:".$value["passwd"];
                             }
                          }else{
                              $contentStr = "抱歉！没有该资源";
                          }
                       }
                      //  文档
                       if($ruler == 2){
                            $data=Db::name('upload_doc_source')->where('description','like', "%".$content."%")->limit(10)->select();
                          if(!empty($data)){
                              

                             foreach ($data as $key=>$value){
                                 $contentStr = $contentStr."\n\n"."描述:".$value["description"]." 链接:"."http://".$_SERVER["HTTP_HOST"].$value["file_path"]." 密码:".$value["passwd"];
                             }
                          }else{
                              $contentStr = "抱歉！文档未能搜索到";
                          }
                       }
                      //   图片
                       if($ruler == 3){
                            $data=Db::name('upload_file_source')->where('description','like', "%".$content."%")->limit(10)->select();
                          if(!empty($data)){
                            
                             foreach ($data as $key=>$value){
                                 $contentStr = $contentStr."\n\n"."描述:".$value["description"].":"."http://".$_SERVER["HTTP_HOST"].$value["file_path"];
                             }
                          }else{
                              $contentStr = "抱歉！图片未能搜索到";
                          }
                         
                       }
                       
                       
                    //   可拓展其他接口****************
                       
                       return $contentStr;
  }



// 图片二值化和灰度处理
function graypng($resimg) {
    header("Content-type: image/png");
$image = imagecreatefromstring( file_get_contents( $resimg));
$img_width = ImageSX($image);
$img_height = ImageSY($image);
for ($y = 0; $y <$img_height; $y++) {
   for ($x = 0; $x <$img_width; $x++) {
    $gray = (ImageColorAt($image, $x, $y) >> 8) & 0xFF;
    imagesetpixel ($image, $x, $y, ImageColorAllocate ($image, $gray,$gray,$gray));
   }
}
imagepng($image,$resimg,9);
imagedestroy($image);
}



// 图像文字提取函数

private function getText($url, $MsgId){
        
         // 永远执行
        ignore_user_abort(true);
        set_time_limit(0);

    do{
        $url = preg_replace("/ /", "%20", $url); 
        $filename = $_SERVER['DOCUMENT_ROOT'] . "/upload/image/".date("dMYHis").'.png';//文件名称生成
        ob_start();//打开输出
        readfile($url);//输出图片文件-------打开allow_url_fopen 和 uaer-gaen 拓展 在php.init中
        $img = ob_get_contents();//得到浏览器输出
        ob_end_clean();//清除输出并关闭
        $size = strlen($img);//得到图片大小
        $fp2 = @fopen($filename, "a");
        fwrite($fp2, $img);//向当前目录写入图片文件，并重新命名
        fclose($fp2);
        // 图片二值化和灰度处理
        $this->graypng($filename);
        // ***************************防止微信5请求不响应解决方案*************************************
        // 取缓存
        if(Cache::get('content') && Cache::get('MsgId') && Cache::get('MsgId') == $MsgId){
            echo "****获取缓存********";
            // 获取缓存成功
            $data = Cache::get('content');
            // 删除缓存
            Cache::rm('content');
            Cache::rm('MsgId');
            // 删除文件
            unlink($filename);
            break;
        }else{
             echo "****没有缓存********";
             // 没有缓存
             $lang = ['eng_fast', 'chi_sim_fast'];
             $a = new TesseractOCR();
             $a->lang($lang);
             $a->image($filename);
             $data = $a->run();
             
             error_log("php程序正在执行.....", 0);
             
             if(!empty($data)){
                 // 跳出循环
                 // dump( $data);
                 //设置缓存------缓存时间为15s
                 Cache::set('content',$data,15);
                 Cache::set('MsgId', $MsgId,15);
                 
                 error_log(date('Y-m-d h:i:s', time()), 0);
                 error_log("php程序已经停止运行", 0);
                 error_log(Cache::get('content'), 0);
                 
                 // 删除文件
                 unlink($filename);
                 break;
             }
          }
           // 删除文件
           unlink($filename);
    }while(true);
           
    
       
        // echo $data;
        if(empty($data)){
            // 为空时，说明该图片没有文字
            return null;
        }
        return $data;
}


//搜索题目答案函数
public  function  search($question){

//查询数据
$data=Db::name('answer_source')->where('question','like', "%".$question."%")->find();
if(!empty($data)){
return "问题:".$data["question"]."\n答案:".$data["answer"];
}


//调用第三方接口↓↓↓↓↓

//咩有查询到
return "抱歉！未能查询到！";
}


}

?>